/*
 * @(#)PhotoHandler.java 0.0.1-SNAPSHOT
 * Copyright Group B
 */

package grupb.upf.XMLHandlers;

import grupb.upf.XMLObjects.MetadataDC;
import grupb.upf.XMLObjects.Photo;
import grupb.upf.XMLObjects.Tagging;
import grupb.upf.XMLObjects.impl.PersonalTag;
import grupb.upf.XMLObjects.impl.PredefinedTag;
import java.util.List;
import java.util.Vector;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

/**
 * <p>This class cointains the functions to parsing the photo XML elements
 * into Java objects.</p>
 *
 * @version    0.0.1-SNAPSHOT
 * @author     Group B
 */
public final class PhotoHandler extends org.xml.sax.helpers.DefaultHandler {

    /**
     * The logger. A new logger <code>grupb.upf.XMLHandlers.PhotoHandler</code>
     * is created to add the logs of this Content.
     */
    private static final Log LOG = LogFactory.getLog(PhotoHandler.class);
    /**
     * The number of coordenates X1, X2, Y1, Y2.
     */
    private static final int NCOORDENATES = 4;
    /**
     * The number of coordenates X1, X2, Y1, Y2.
     */
    private static final int X1 = 0;
    /**
     * The number of coordenates X1, X2, Y1, Y2.
     */
    private static final int X2 = 1;
    /**
     * The number of coordenates X1, X2, Y1, Y2.
     */
    private static final int X3 = 2;
    /**
     * The number of coordenates X1, X2, Y1, Y2.
     */
    private static final int X4 = 3;
    /**
     * The object Photo where we are going to parse the XML.
     */
    private Photo photo;
    /**
     * The StringBuffer to read the XML elements.
     */
    private StringBuffer accumulator;
    /**
     * The medatada of the photo.
     */
    private MetadataDC metadata = new grupb.upf.XMLObjects.impl.MetadataDC();
    /**
     * The auxiliar to create predefined tags.
     */
    private PredefinedTag auxPredTag = new grupb.upf.XMLObjects.impl
            .PredefinedTag();
    /**
     * The auxiliar to create personal tags.
     */
    private PersonalTag auxPersTag = new grupb.upf.XMLObjects.impl
            .PersonalTag();
    /**
     * The list of predefined tags.
     */
    private List predefinedTags = new Vector();
    /**
     * The list of personal tags.
     */
    private List personalTags = new Vector();
    /**
     * The tags of the new (predefined and personal tags).
     */
    private Tagging tags = new grupb.upf.XMLObjects.impl.Tagging();

    /**
     * This is the constructor of the Handler.
     */
    public PhotoHandler() {
        this.photo = new grupb.upf.XMLObjects.impl.Photo();
    }

    /**
     * This is the constructor of the Handler.
     * @param ph is the object where the XML will be parsed
     */
    public PhotoHandler(final Photo ph) {
        this.photo = ph;
    }

    /**
     * This function is called at the beginning and it creates the accumulator.
     */
    @Override
    public void startDocument() {
        accumulator = new StringBuffer();
    }

    /**
     * When the parser encounters plain text (not XML elements),
     * it calls this method, which accumulates the text in a string buffer.
     * Note that this method may be called in multiple times.
     * @param buffer is the buffer
     * @param start the initial point
     * @param length the length of the accumulator
     */
    @Override
    public void characters(final char[] buffer, final int start,
            final int length) {
        accumulator.append(buffer, start, length);
    }

    /**
     * At the beginning of each new element, erase any accumulated text.
     * @param namespaceURL the namespaceURL of the element
     * @param localName the name of the element
     * @param qname the qname of the element
     * @param attributes the attributes of the element
     */
    @Override
    public void startElement(final String namespaceURL, final String localName,
            final String qname, final Attributes attributes) {
        accumulator.setLength(0);
        if (localName.equals("photo")) {
            photo.setID(Integer.parseInt(attributes.getValue(0)));
        } else if (localName.equals("ontology_tag")) {
            auxPredTag = new PredefinedTag();
        } else if (localName.equals("predefined_tag")) {
            if (attributes.getLength() == NCOORDENATES) {
                int [] n = new int[NCOORDENATES];
                for (int i = 0; i < NCOORDENATES; i++) {
                    n[i] = Integer.parseInt(attributes.getValue(i));
                }
                auxPredTag.setCoordenates(n[X1], n[X2], n[X3], n[X4]);
            }
        } else if (localName.equals("personal_tag")) {
            auxPersTag = new PersonalTag();
            if (attributes.getLength() == NCOORDENATES) {
                int [] n = new int[NCOORDENATES];
                for (int i = 0; i < NCOORDENATES; i++) {
                    n[i] = Integer.parseInt(attributes.getValue(i));
                }
                auxPersTag.setCoordenates(n[X1], n[X2], n[X3], n[X4]);
            }
        }
    }

    /**
     * Take special action when reach the end of selected elements.
     * In this case the accumulated text is stored in the video object.
     * @param namespaceURL the namespaceURL of the element
     * @param localName the name of the element
     * @param qname the qname of the element
     */
    @Override
    public void endElement(final String namespaceURL, final String localName,
            final String qname) {
        if (localName.equals("file_url")) {
            photo.setURL(accumulator.toString().trim());
        } else if (localName.equals("file_url")) {
            photo.setURL(accumulator.toString().trim());
        } else if (localName.equals("dc.title")
                || localName.equals("dc.subject")
                || localName.equals("dc.description")
                || localName.equals("dc.type")
                || localName.equals("dc.source")
                || localName.equals("dc.relation")
                || localName.equals("dc.coverage")) {
            metadata.setContentProperty(localName,
                    accumulator.toString().trim());
        } else if (localName.equals("dc.creator")
                || localName.equals("dc.publisher")
                || localName.equals("dc.contributor")
                || localName.equals("dc.rights")) {
            metadata.setIntellectualProperty(localName,
                    accumulator.toString().trim());
        } else if (localName.equals("dc.date")
                || localName.equals("dc.format")
                || localName.equals("dc.identif ier")
                || localName.equals("dc.language")) {
            metadata.setInstantiationProperty(localName,
                    accumulator.toString().trim());
        } else if (localName.equals("metadata_dc")) {
            photo.setMetadataDC(metadata);
        } else if (localName.equals("category")) {
            auxPredTag.setCategory(accumulator.toString().trim());
        } else if (localName.equals("predefined_tag")) {
            auxPredTag.setTag(accumulator.toString().trim());
        } else if (localName.equals("ontology_tag")) {
            predefinedTags.add(auxPredTag);
        } else if (localName.equals("ontology_tags")) {
            tags.setPredefinedTags(predefinedTags);
        } else if (localName.equals("personal_tag")) {
            auxPersTag.setTag(accumulator.toString().trim());
            personalTags.add(auxPersTag);
        } else if (localName.equals("personal_tags")) {
            tags.setPersonalTags(personalTags);
        } else if (localName.equals("tags")) {
            photo.setTags(tags);
        }
    }

    /**
     * This function is called at the end.
     */
    @Override
    public void endDocument() {
    }

    /**
     * Function to catch warnings.
     * @param exception a SAXParseException
     */
    @Override
    public void warning(final SAXParseException exception) {
        StringBuffer ex = new StringBuffer("Line ")
                .append(exception.getLineNumber())
                .append(": ")
                .append(exception.getMessage());
        LOG.warn(ex);
    }

    /**
     * Function to catch errors.
     * @param exception a SAXParseException
     */
    @Override
    public void error(final SAXParseException exception) {
        StringBuffer ex = new StringBuffer("Line ")
                .append(exception.getLineNumber())
                .append(": ")
                .append(exception.getMessage());
        LOG.error(ex);
    }

    /**
     * Function to catch Fatal Errors.
     * @param exception a SAXParseException
     * @throws SAXException to catch the exception
     */
    @Override
    public void fatalError(final SAXParseException exception)
            throws SAXException {
        StringBuffer ex = new StringBuffer("Line ")
                .append(exception.getLineNumber())
                .append(": ")
                .append(exception.getMessage());
        LOG.fatal(ex);
        throw(exception);
    }
}
